﻿using System;
using System.IO;
using System.Text.RegularExpressions;
using System.Text;

namespace HTMLPlugin
{
    /// <summary>
    /// HTML highlighter
    /// </summary>
    public class HTMLPlugin : Interface.IPlugin
    {
        /// <summary>
        /// Plugin name
        /// </summary>
        public string Name
        {
            get
            {
                return "Sourcecode2HTML Plugin for *.html (HTML)";
            }
        }
        /// <summary>
        /// Plugin version
        /// </summary>
        public string Version
        {
            get
            {
                return "0.1";
            }
        }
        /// <summary>
        /// Author
        /// </summary>
        public string Author
        {
            get
            {
                return "Евгений Кукло, Евгений Казбан, Власов Иван";
            }
        }
        /// <summary>
        /// Language name
        /// </summary>
        public string LanguageName
        {
            get
            {
                return "HTML";
            }
        }

        /// <summary>
        /// Extension
        /// </summary>
        public string Extension
        {
            get
            {
                return "html";
            }
        }

        /// <summary>
        /// Check matches and convert to HTML tags
        /// </summary>
        /// <param name="match">Match</param>
        /// <returns>Converted string</returns>
        private string AttributeMatchEval(Match match)
        {
            if (match.Groups[1].Success)
                return "<span class=\"kwrd\">" + match.ToString() + "</span>";

            if (match.Groups[2].Success)
                return "<span class=\"attr\">" + match.ToString() + "</span>";

            return match.ToString();
        }

        private Regex attribRegex;

        /// <summary>
        /// Check matches and convert to HTML tags
        /// </summary>
        /// <param name="match">Match</param>
        /// <returns>Converted string</returns>
        protected string MatchEval(Match match)
        {
            if (match.Groups[1].Success)
            {
                StringReader reader = new StringReader(match.ToString());
                string line;
                StringBuilder sb = new StringBuilder();
                while ((line = reader.ReadLine()) != null)
                {
                    if (sb.Length > 0)
                    {
                        sb.Append("\n");
                    }
                    sb.Append("<span class=\"rem\">");
                    sb.Append(line);
                    sb.Append("</span>");
                }
                return sb.ToString();
            }
            if (match.Groups[2].Success)
            {
                return "<span class=\"kwrd\">" + match.ToString() + "</span>";
            }
            if (match.Groups[3].Success)
            {
                return "<span class=\"html\">" + match.ToString() + "</span>";
            }
            if (match.Groups[4].Success)
            {
                return attribRegex.Replace(match.ToString(),
                    new MatchEvaluator(this.AttributeMatchEval));
            }
            if (match.Groups[5].Success)
            {
                return "<span class=\"attr\">" + match.ToString() + "</span>";
            }
            return match.ToString();
        }

        /// <summary>
        /// Converts source code to HTML string
        /// </summary>
        /// <param name="input">Input string</param>
        /// <param name="linenumbers">Draw line numbers</param>
        /// <returns>Returns HTML string</returns>
        public string HighlightKeywords(string input, bool linenumbers)
        {
            const string regComment = @"&lt;!--.*?--&gt;";
            const string regTagDelimiter = @"(?:&lt;/?!?\??(?!%)|(?<!%)/?&gt;)+";
            const string regTagName = @"(?<=&lt;/?!?\??(?!%))[\w\.:-]+(?=.*&gt;)";
            const string regAttributes = @"(?<=&lt;(?!%)/?!?\??[\w:-]+).*?(?=(?<!%)/?&gt;)";
            const string regEntity = @"&amp;\w+;";
            const string regAttributeMatch = @"(=?"".*?""|=?'.*?')|([\w:-]+)";

            string regAll = "(" + regComment + ")|("
                + regTagDelimiter + ")|(" + regTagName + ")|("
                + regAttributes + ")|(" + regEntity + ")";
            Regex CodeRegex;
            CodeRegex = new Regex(regAll, RegexOptions.IgnoreCase | RegexOptions.Singleline);
            attribRegex = new Regex(regAttributeMatch, RegexOptions.Singleline);

            StringBuilder sb = new StringBuilder(input);
            sb.Replace("&", "&amp;");
            sb.Replace("<", "&lt;");
            sb.Replace(">", "&gt;");
            sb.Replace("\t", string.Empty.PadRight(4));
            input = CodeRegex.Replace(sb.ToString(), new MatchEvaluator(this.MatchEval));
            sb = new StringBuilder();

            sb.Append("<div class=\"csharpcode\">\n");
            StringReader reader = new StringReader(input);
            int i = 0;
            string spaces = "    ";
            int order;
            string line;
            while ((line = reader.ReadLine()) != null)
            {
                i++;
                if ((i % 2) == 1)
                {
                    sb.Append("<pre class=\"alt\">");
                }
                else
                {
                    sb.Append("<pre>");
                }
                order = (int)Math.Log10(i);
                sb.Append("<span class=\"lnum\">"
                    + spaces.Substring(0, 3 - order) + i.ToString()
                    + ":  </span>");
                if (line.Length == 0)
                    sb.Append("&nbsp;");
                else
                    sb.Append(line);
                sb.Append("</pre>\n");
            }
            reader.Close();
            sb.Append("</div>");
            return sb.ToString();
        }
    }
}
